package com.nebrija.riif.model;


import java.util.Calendar;
import java.util.HashMap;
import java.util.Set;

public class Timeline implements RIIFElement, RIIFPropertiesContainer {

	/** name of the timeline */
	protected String name = "";	
	
	/** Namespace for all the states included in this timeline*/
	private HashMap<String,State> states = new HashMap<String,State>();	
	
	private TimelineExecution execution = new RealTimelineExecution(this);
	
	public Timeline(String name){
		this.name=name;
	}
	
	/**
	 * Function that adds a state to this timeline. It is added to the state list
	 * @param st the state to be added
	 * @return an error string or an empty string if no error
	 */
	public String addState(State st) {
		if (st==null){
			return "Null";
		}
		if (st.getName()==null || st.getName().equals("")){
			return "Null";
		}
		if (hasState(st)){
			return "A constant with that name already exists in this component"; // TODO Internationalization
		}
		states.put(st.getName(), st);
		return "";
	}
	
	/**
	 * Check if a state exists
	 * @param st state
	 * @return true if it exists, false otherwise
	 */	
	public boolean hasState(State st) {
		if (states.get(st.getName())!=null){
			return true;
		}
		return false;
	}	
	

	
	@Override
	public RIIFProperties getPropertiesElement(String name) {
		return states.get(name);
	}

	@Override
	public RIIFElement getElement(String name) {
		return states.get(name);
	}

	@Override
	public String addConstant(Constant co) {
		return null;
	}

	@Override
	public String addParameter(Parameter par) {
		return null;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public void resolve(RIIFElement container) {
		for (State element: states.values()){
			element.resolve(this);
		}
	}

	@Override
	public void clear(RIIFElement container) {
		for (State element: states.values()){
			element.clear(this);
		}
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder(getName());
		
		sb.append("\n->STATES: \n");
		Set<String> constantNames = states.keySet();
		for(String name: constantNames){
			sb.append("\t").append(states.get(name).toString());
		}
		
		return sb.toString();
	}

	public Double getTimeSinceLastTransition(TimeStrings ts) {
		return getExecution().getTimeSinceLastTransition(ts);
	}

	public State getCurrentState() {
		return execution.getCurrentState();
	}

	public TimelineExecution getExecution() {
		return execution;
	}

	public void setExecution(TimelineExecution execution) {
		this.execution = execution;
	}
	
	public State getInitialState(){
		for (State state: this.states.values()){
			if (state.getStateType()==StateType.initial){
				return state;
			}
		}
		return null;
	}

	public Double getTimeSince(ValueTimeUnit vtu, TimeStrings ts) {
		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(0);
		if(vtu.getTimeUnit().equals(TimeStrings.ms)){
			cal.setTimeInMillis((long)vtu.getValue());
		}else{
			cal.add(TimeStrings.timeStringsToCalendar(vtu.getTimeUnit()),(int)vtu.getValue());
		}
		return execution.getTimeSince(cal, ts);
	}

	@Override
	public int getChildCount() {
		return states.size();
	}

	@Override
	public Set<String> getElementNames() {
		return states.keySet();
	}
	

}
